import React, { PropTypes, Component} from 'react';
import ReactDOM from 'react-dom';
import Animate from 'rc-animate';
import objectAssign from 'object-assign';
import mixins from '../mixins/mixins'

class Box extends Component {

    hideByBack(event) {
        if (this.props.closeByBack) {
            this.props.hide();
        }
    }

    stop(event){
        event.stopPropagation();
    }

    render() {

        const style = {
            visibility: this.props.isOpen ? 'visible' : 'hidden'
        };

        return (<div  className={'modal ' + this.props.type + (this.props.background?' modal-background':'')} style={style} onClick={this.hideByBack.bind(this) }>
                    <div className="modal-content" style={this.props.style} onClick={this.stop.bind(this)}>
                        {this.props.closeIcon ? <a href="javascript:;" className="closeIcon" onClick={this.props.hide}><i className="icon icon-fork"></i></a> : ''}
                        {this.props.children}
                    </div>
                </div>);
    }
}

Box.PropTypes = {
    isOpen: PropTypes.bool,
    type: PropTypes.string,
    children: PropTypes.node,
    style: PropTypes.object,
    closeIcon: PropTypes.bool
}

//记录当前已经开过几个modal了，以便判断是否需要显示背景
let mNum = 0;

class ModalWarp extends Component {

    constructor(props) {
        super(props);
        this.state = objectAssign({}, {
            isOpen: false,
            type: 'nomal',
            background: true,
            closeIcon: true,
            closeByBack: true,
            unmountDom:true
        }, props);

        //绑定this指针
        this.onEnter = this.onEnter.bind(this);
        this.onLeave = this.onLeave.bind(this);
        this.hide = this.hide.bind(this);
        this.show = this.show.bind(this);
    }

    onEnter() {
        if (Object.prototype.toString.call(this.props.enterAfter) == "[object Function]") {
            this.props.enterAfter();
        }
    }

    onLeave() {
        mNum--;
        if (Object.prototype.toString.call(this.props.leaveAfter) == "[object Function]") {
            this.props.leaveAfter();
        }

        this.state.unmountDom&&this.props.unmount();

        if(!mNum){
            document.body.style.paddingRight='';
            mixins.removeClass(document.body,'modal-open');
        }
    }

    hide() {
        if (Object.prototype.toString.call(this.props.leaveBefore) == "[object Function]") {
            this.props.leaveBefore();
        }
        this.setState({
            isOpen: false
        });
    }

    show() {
        mNum++;
        if (Object.prototype.toString.call(this.props.enterBefore) == "[object Function]") {
            this.props.enterBefore();
        }
        this.setState({
            isOpen: true
        });
    }

    componentDidMount() {
        const self = this;
        const warpElement=ReactDOM.findDOMNode(this);

        //锁定body并且加一个padding防止body抖动
        mixins.addClass(document.body,'modal-open');
        //当有滚动条时加一个padding
        if(document.body.style.overflow!="hidden"&&document.body.scroll!="no"&&document.body.scrollHeight>document.body.offsetHeight){
            document.body.style.paddingRight=mixins.scrollWidth+'px';
        }

        const contentHeight=warpElement.querySelector('.modal-content').clientHeight;

        //因为默认高度是0.3所有这里和0.7对比
        if(contentHeight>warpElement.clientHeight*0.7){
            warpElement.querySelector('.modal-content').style.top='5%';
            warpElement.querySelector('.modal-content').style.marginBottom='20px';
        }

        Array.prototype.map.call(warpElement.querySelectorAll('[data-close]'),function(element){
            element.onclick = function () {
                self.hide();
            }
        });

    }

    render() {
        return (
            <Animate
                component=""
                showProp="isOpen"
                onEnter={this.onEnter}
                onLeave={this.onLeave}
                transitionName="modal-transiton"
                >
                <Box {...this.state} {...this.props} background={(mNum > 1) ? false : this.state.background} hide={this.hide} ref="box"/>
            </Animate>
        );
    }
}

class Modal extends Component {

    show() {
        if(!this.modal){
            this.node = document.createElement('div');
            document.body.appendChild(this.node);

            this.renderPortal();
        }
        this.modal.show();
    }

    hide() {
        this.modal.hide();
    }

    componentWillReceiveProps(nextProps) {
        if(!this.modal){
            this.node = document.createElement('div');
            document.body.appendChild(this.node);

            this.renderPortal();
        }
        this.renderPortal(nextProps);
    }


    unmount() {
        this.props.unmount&&this.props.unmount();
        ReactDOM.unmountComponentAtNode(this.node);
        document.body.removeChild(this.node);
    }

    renderPortal(props) {
        this.modal = ReactDOM.render(
            <ModalWarp {...this.props} {...props}  unmount={this.unmount.bind(this) }/>,
            this.node
        )
    }

    render() {
        return React.DOM.noscript();
    }
}


Modal.PropTypes = {
    enterAfter: PropTypes.func,
    leaveAfter: PropTypes.func,
    enterBefore: PropTypes.func,
    leaveBefore: PropTypes.func
}

export default Modal;

module.exports.modal = function (props) {
    const node = document.createElement('div');
    document.body.appendChild(node);

    class Temp extends Component {
        componentDidMount() {
            this.refs.modal.show();
        }

        show() {
            this.refs.modal.show();
        }

        hide() {
            this.refs.modal.hide();
        }

        unmount() {
            ReactDOM.unmountComponentAtNode(node);
        }

        render() {
            return <Modal {...props} ref="modal" unmount={this.unmount.bind(this) }/>
        }

    }

    document.body.removeChild(node);

    return ReactDOM.render(
        <Temp {...props} />,
        node
    );

}

